package com.web.kdl.util;

import java.util.Formatter;

public class ModbusUtil {

    /**
     * 构建 Modbus TCP 读保持寄存器（FC=03）请求报文
     *
     * @param transactionId       事务ID (0~65535)
     * @param unitId              从设备地址 (1~247)
     * @param startRegisterAddress 起始寄存器地址 (如 40001 -> 实际地址为 40000，传入时注意减1？视协议定义而定)
     *                            注：此处假设直接使用寄存器编号对应的内部地址（例如 40001 对应地址 0）
     * @param quantity            读取寄存器数量 (1~125)
     * @return Hex 字符串，如 "06 E4 00 00 00 06 01 03 9C 41 00 64"
     */
    public static String buildReadHolding(
            int transactionId,
            int unitId,
            int startRegisterAddress,
            int quantity) {

        // 参数校验
        if (transactionId < 0 || transactionId > 65535) {
            throw new IllegalArgumentException("站点id must be 0-65535");
        }
        if (quantity < 1 || quantity > 125) {
            throw new IllegalArgumentException("寄存器个数 must be 1-125 (Modbus limit)");
        }


        Formatter fmt = new Formatter();

        // 1. Transaction ID (2 bytes, big-endian)
        fmt.format("%02X ", (transactionId >> 8) & 0xFF); //右移8位 获取高8位
        fmt.format("%02X ", transactionId & 0xFF); //取低8位

//        fmt.format("06 E4 ");
        // 2. Protocol ID (2 bytes, always 0 for Modbus TCP)
        fmt.format("00 00 ");

        // 3. Length: 后续字节数 = 6 (UnitID + FC + Addr(2) + Qty(2))
        fmt.format("00 06 ");

        // 4. Unit ID (1 byte)
        fmt.format("%02X ", unitId);

        // 5. Function Code (1 byte)
        fmt.format("03 ");

        // 6. Starting Address (2 bytes, big-endian)
        fmt.format("%02X ", (startRegisterAddress >> 8) & 0xFF);
        fmt.format("%02X ", startRegisterAddress & 0xFF);

        // 7. Quantity (2 bytes, big-endian)
        fmt.format("%02X ", (quantity >> 8) & 0xFF);
        fmt.format("%02X", quantity & 0xFF); // 最后一个不加空格

        return fmt.toString();
    }

    /**
     * 构造 Modbus TCP 写单个保持寄存器请求报文（Function Code 0x06）
     * 输出为带空格的十六进制字符串，如："00 01 00 00 00 06 01 06 00 01 00 FF"
     *
     * 报文结构：
     * [TXID:2B] [Proto:2B] [Length:2B] [Unit ID:1B] [FC:1B] [Addr:2B] [Value:2B]
     *
     * @param transactionId 事务ID (0-65535)
     * @param unitId        从站地址/设备地址 (1-247)
     * @param registerAddress 寄存器地址 (如 40001 对应 0x0000)
     * @param value         要写入的值 (0-65535)
     * @return 格式化后的十六进制字符串（每字节间有空格）
     */
    public static String buildWriteSingleRegister(
            int transactionId,
            int unitId,
            int registerAddress,
            int value) {

        // 参数校验
        if (transactionId < 0 || transactionId > 65535) {
            throw new IllegalArgumentException("Transaction ID must be between 0 and 65535");
        }
        if (unitId < 1 || unitId > 247) {
            throw new IllegalArgumentException("Unit ID (slave address) must be 1-247");
        }
        if (registerAddress < 0 || registerAddress > 65535) {
            throw new IllegalArgumentException("Register address must be 0-65535");
        }
        if (value < 0 || value > 65535) {
            throw new IllegalArgumentException("Value must be 0-65535");
        }

        Formatter fmt = new Formatter();

        // 1. Transaction ID (2 bytes, big-endian)
        fmt.format("%02X %02X ",
                (transactionId >> 8) & 0xFF,
                transactionId & 0xFF);

        // 2. Protocol ID (2 bytes, always 0 for Modbus TCP)
        fmt.format("00 00 ");

        // 3. Length: 后续字节数 = 6 (UnitID + FC + Addr(2) + Value(2))
        fmt.format("00 06 ");

        // 4. Unit ID (1 byte)
        fmt.format("%02X ", unitId);

        // 5. Function Code (1 byte) - Write Single Register
        fmt.format("06 ");

        // 6. Register Address (2 bytes, big-endian)
        fmt.format("%02X %02X ",
                (registerAddress >> 8) & 0xFF,
                registerAddress & 0xFF);

        // 7. Value to write (2 bytes, big-endian)
        fmt.format("%02X %02X",
                (value >> 8) & 0xFF,
                value & 0xFF); // 最后一个不加空格

        return fmt.toString();
    }
}